package tool;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * @author martin
 * Simple calendar
 */
public final class SimpleCal {
	/*properties*/
	private final Calendar _cal;
	private final SimpleCal _fst;

	/*constructor*/
	/**
	 * private constructor
	 * use static factory
	 * @param month
	 */
	private SimpleCal(final Calendar month){
		_cal = month;
		if(getDay() == 1)
			_fst = this;
		else
			_fst = onDay(1);
		
	}

	/*static factory*/
	/**
	 * static factory from todays date
	 * @return new SimpleCal set on today date
	 */
	public static SimpleCal fromToday(){
		return new SimpleCal(new GregorianCalendar());
	}
	/**
	 * static factory from given date
	 * @param day as int
	 * @param month as int
	 * @param year as int
	 * @return new SimpleCal set on given date
	 */
	public static SimpleCal fromDayMonthYear(int day, int month, int year){
		return new SimpleCal(new GregorianCalendar(year, month-1, day));
	}
	
	/**
	 * static factory from given date time
	 * @param day as int
	 * @param month as int
	 * @param year as int
	 * @param hour as int
	 * @param minute as int
	 * @return new simplecal
	 */
	public static SimpleCal fromDayMonthYearHourMinute(int day, int month, int year, int hour, int minute){
		return new SimpleCal(new GregorianCalendar(year, month-1, day, hour, minute));
	}
	
	/**
	 * static factory from calendar
	 * @param cal as Calendar
	 * @return SimpleCal
	 */
	public static SimpleCal fromCalendar(final Calendar cal){
		return new SimpleCal((Calendar)cal.clone());
	}
	
	/*getter*/

	/**
	 * getter
	 * @return day of month
	 */
	public int getDay(){
		return _cal.get(Calendar.DAY_OF_MONTH);
	}

	/**
	 * getter
	 * @return month number
	 */
	public int getMonth(){
		return _cal.get(Calendar.MONTH)+1;
	}

	/**
	 * getter
	 * @return year as int
	 */
	public int getYear(){
		return _cal.get(Calendar.YEAR);
	}

	/**
	 * getter
	 * @return week day number
	 */
	public int weekDay(){
		return _cal.get(Calendar.DAY_OF_WEEK);
	}
	
	/**
	 * getter
	 * @return hour as int
	 */
	public int getHour(){
		return _cal.get(Calendar.HOUR_OF_DAY);
	}
	
	/**
	 * getter
	 * @return minute as int
	 */
	public int getMinute(){
		return _cal.get(Calendar.MINUTE);
	}
	
	/**
	 * getter
	 * @return quarter as int (0, 15, 30, 45)
	 */
	public int getQuarter(){
		return _cal.get(Calendar.MINUTE)/15;
	}

	/*immutator*/
	
	/**
	 * change day
	 * @param nuday as int
	 * @return new simplecal with new day
	 */
	public SimpleCal onDay(int nuday){
		return SimpleCal.fromDayMonthYear(nuday,getMonth(), getYear());
	}

	/**
	 * change month
	 * @param numonth as int
	 * @return new simplecal with new month
	 */
	public SimpleCal onMonth(int numonth){
		return SimpleCal.fromDayMonthYear(getDay(),numonth, getYear());
	}

	/**
	 * change year
	 * @param nuyear as int
	 * @return new simplecal with new year
	 */
	public SimpleCal onYear(int nuyear){
		return SimpleCal.fromDayMonthYear(getDay(),getMonth(), nuyear);
	}
	
	/**
	 * change time
	 * @param hour as int
	 * @param minute as int
	 * @return new simplecal
	 */
	public SimpleCal onTime(int hour, int minute){
		return SimpleCal.fromDayMonthYearHourMinute(getDay(),getMonth(), getYear(), hour, minute);

	}

	/*construct calendar*/
	/**
	 * getter
	 * @return weekday of the first of the month
	 */
	public int firstWeekDay(){
		return _fst.weekDay();
	}

	/**
	 * getter
	 * @return number of the in the current month
	 */
	public int lastMonthDay(){
		return _cal.getActualMaximum(Calendar.DAY_OF_MONTH);
	}

	//create DAY object
	/**
	 * mapping the month into a table
	 * @param col as int column
	 * @param row as int row
	 * @return day number
	 */
	public Integer getDayAt(int col, int row){
    	int day = row*7 + col - firstWeekDay()+2;
    	if (day < 1 || (day > lastMonthDay()))
    		return null;
        return day;
	}
	
	/*string getter*/
	private static final SimpleDateFormat dayFmt = new SimpleDateFormat("EEEE dd MMMM yyyy");
	private static final SimpleDateFormat timeFmt = new SimpleDateFormat("HH:mm");
	private static final SimpleDateFormat timeSqlFmt = new SimpleDateFormat("HH:mm:ss");
  private static final SimpleDateFormat dateSqlFmt = new SimpleDateFormat("yyyy-MM-dd");

	/**
	 * string format
	 * @return return sql formated string date
	 */
	public String getStrSql(){
		return new String() + getYear() + "-" + (getMonth()) + "-" + getDay();
	}
	
	/**
	 * string format
	 * @return human readable string date
	 */
	public String getDateStr(){
		return dayFmt.format(_cal.getTime());
	}

	/**
	 * string format
	 * @return human readable clock string
	 */
	public String getClockStr(){
		return timeFmt.format(_cal.getTime());
	}
	
	/**string format
	 * @return sql formated time string
	 */
	public String getClockSql(){
		return timeSqlFmt.format(_cal.getTime());
	}
  
  public String getDateSql(){
    return dateSqlFmt.format(_cal.getTime());
  }
	
  public Date getJavaDate(){
    return _cal.getTime();
  }
  
	/*static function*/
	public static String timeToSql(final Date time){
		return timeSqlFmt.format(time);
	}
  
  public static String dateToSql(final Date date){
    return dateSqlFmt.format(date);
  }
  
	private static final java.text.DateFormatSymbols token = new java.text.DateFormatSymbols();
	/**
	 * static function
	 * @param i as week day
	 * @return token name of the week day
	 */
	public static String getWeekDayStr(int i){
		return token.getWeekdays()[i];
	}
	/**
	 * static function
	 * @param i as month
	 * @return token name of the month
	 */
	public static String getMonthStr(int i){
		return token.getMonths()[i-1];
	}
	
	/**
	 * build calendar from string sql formated time
	 * @param clk as time sql format
	 * @return Calendar
	 * @throws ParseException
	 */
	public static Calendar fromClockStr(final String clk) throws ParseException{
		Calendar cal = new GregorianCalendar();
		cal.setTime(timeSqlFmt.parse(clk));
		return cal;
	}

	/*test*/
	public static void main(String[] args) {
		SimpleCal c = SimpleCal.fromToday();
		System.out.println(SimpleCal.getMonthStr(c.getMonth()));
		for (int i=1;i<=7;i++)
			System.out.print(SimpleCal.getWeekDayStr(i) + "|");
		System.out.println();
		for (int row=0;row<6;row++){
			for (int col=0;col<7;col++)
				System.out.print(c.getDayAt(col,row) + "|");
			System.out.println();
		}

		System.out.println(SimpleCal.fromDayMonthYearHourMinute(18, 03, 2013, 13, 30).weekDay());
		System.out.println(SimpleCal.getMonthStr(3));
	}

}
